package com.yyy.tcc.dao;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class AccountDao {
    private DataSource dataSource;

    public AccountDao(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public boolean tryFreeze(String userId, BigDecimal amount) throws SQLException {
        Connection conn = dataSource.getConnection();
        try {
            conn.setAutoCommit(false);

            // 检查并锁定账户
            String checkSql = "SELECT balance, freeze_amount FROM account WHERE user_id = ? FOR UPDATE";
            try (PreparedStatement ps = conn.prepareStatement(checkSql)) {
                ps.setString(1, userId);
                ResultSet rs = ps.executeQuery();
                if (!rs.next()) {
                    conn.rollback();
                    return false;
                }

                BigDecimal balance = rs.getBigDecimal("balance");
                BigDecimal frozenAmount = rs.getBigDecimal("freeze_amount");

                if (balance.compareTo(amount) < 0) {
                    conn.rollback();
                    return false;
                }

                // 更新余额和冻结金额
                String updateSql = "UPDATE account SET balance = balance - ?, freeze_amount = freeze_amount + ?, version = version + 1 WHERE user_id = ?";
                try (PreparedStatement updatePs = conn.prepareStatement(updateSql)) {
                    updatePs.setBigDecimal(1, amount);
                    updatePs.setBigDecimal(2, amount);
                    updatePs.setString(3, userId);
                    updatePs.executeUpdate();
                }
            }

            conn.commit();
            return true;
        } catch (SQLException e) {
            conn.rollback();
            throw e;
        } finally {
            conn.close();
        }
    }

    public boolean confirm(String fromUserId, String toUserId, BigDecimal amount) throws SQLException {
        Connection conn = dataSource.getConnection();
        try {
            conn.setAutoCommit(false);

            // 检查冻结金额
            String checkSql = "SELECT freeze_amount FROM account WHERE user_id = ? FOR UPDATE";
            try (PreparedStatement ps = conn.prepareStatement(checkSql)) {
                ps.setString(1, fromUserId);
                ResultSet rs = ps.executeQuery();
                if (!rs.next() || rs.getBigDecimal("freeze_amount").compareTo(amount) < 0) {
                    conn.rollback();
                    return false;
                }
            }

            // 减少冻结金额
            String updateFromSql = "UPDATE account SET freeze_amount = freeze_amount - ?, version = version + 1 WHERE user_id = ?";
            try (PreparedStatement ps = conn.prepareStatement(updateFromSql)) {
                ps.setBigDecimal(1, amount);
                ps.setString(2, fromUserId);
                ps.executeUpdate();
            }

            // 增加接收方余额
            String updateToSql = "UPDATE account SET balance = balance + ?, version = version + 1 WHERE user_id = ?";
            try (PreparedStatement ps = conn.prepareStatement(updateToSql)) {
                ps.setBigDecimal(1, amount);
                ps.setString(2, toUserId);
                ps.executeUpdate();
            }

            conn.commit();
            return true;
        } catch (SQLException e) {
            conn.rollback();
            throw e;
        } finally {
            conn.close();
        }
    }

    public boolean cancel(String userId, BigDecimal amount) throws SQLException {
        Connection conn = dataSource.getConnection();
        try {
            conn.setAutoCommit(false);

            // 检查冻结金额
            String checkSql = "SELECT freeze_amount FROM account WHERE user_id = ? FOR UPDATE";
            try (PreparedStatement ps = conn.prepareStatement(checkSql)) {
                ps.setString(1, userId);
                ResultSet rs = ps.executeQuery();
                if (!rs.next() || rs.getBigDecimal("freeze_amount").compareTo(amount) < 0) {
                    conn.rollback();
                    return false;
                }
            }

            // 解冻金额
            String updateSql = "UPDATE account SET balance = balance + ?, freeze_amount = freeze_amount - ?, version = version + 1 WHERE user_id = ?";
            try (PreparedStatement ps = conn.prepareStatement(updateSql)) {
                ps.setBigDecimal(1, amount);
                ps.setBigDecimal(2, amount);
                ps.setString(3, userId);
                ps.executeUpdate();
            }

            conn.commit();
            return true;
        } catch (SQLException e) {
            conn.rollback();
            throw e;
        } finally {
            conn.close();
        }
    }

    public BigDecimal getBalance(String userId) throws SQLException {
        try (Connection conn = dataSource.getConnection();
             PreparedStatement ps = conn.prepareStatement("SELECT balance FROM account WHERE user_id = ?")) {
            ps.setString(1, userId);
            ResultSet rs = ps.executeQuery();
            return rs.next() ? rs.getBigDecimal("balance") : BigDecimal.ZERO;
        }
    }
}
